package com.chuanjiabao.wisdom.service;

import android.app.Service;
import android.arch.lifecycle.Observer;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.support.media.ExifInterface;
import android.text.TextUtils;

import com.alibaba.sdk.android.oss.ClientConfiguration;
import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.common.OSSLog;
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSFederationToken;
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider;
import com.alibaba.sdk.android.oss.model.AbortMultipartUploadRequest;
import com.alibaba.sdk.android.oss.model.AbortMultipartUploadResult;
import com.alibaba.sdk.android.oss.model.CompleteMultipartUploadRequest;
import com.alibaba.sdk.android.oss.model.CompleteMultipartUploadResult;
import com.alibaba.sdk.android.oss.model.InitiateMultipartUploadRequest;
import com.alibaba.sdk.android.oss.model.InitiateMultipartUploadResult;
import com.alibaba.sdk.android.oss.model.ListPartsRequest;
import com.alibaba.sdk.android.oss.model.ListPartsResult;
import com.alibaba.sdk.android.oss.model.PartETag;
import com.alibaba.sdk.android.oss.model.PartSummary;
import com.alibaba.sdk.android.oss.model.UploadPartRequest;
import com.alibaba.sdk.android.oss.model.UploadPartResult;
import com.chuanjiabao.wisdom.application.FApplication;
import com.chuanjiabao.wisdom.bean.Constants;
import com.chuanjiabao.wisdom.bean.UpdateFileTeam;
import com.chuanjiabao.wisdom.bean.UpdatePermissionCallBackBean;
import com.chuanjiabao.wisdom.greendao.gen.UpdateFileTeamDao;
import com.chuanjiabao.wisdom.listener.NetworkCallbackImpl;
import com.chuanjiabao.wisdom.util.GsonUtil;
import com.chuanjiabao.wisdom.util.ImageUtil;
import com.chuanjiabao.wisdom.util.LogUtil;
import com.chuanjiabao.wisdom.util.SpResourceUtil;
import com.chuanjiabao.wisdom.util.StringUtil;
import com.chuanjiabao.wisdom.util.TimeHelper;
import com.chuanjiabao.wisdom.util.ToastUtil;
import com.chuanjiabao.wisdom.util.ToolUtil;
import com.lzy.okgo.OkGo;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import kotlin.collections.CollectionsKt;
import okhttp3.Response;

import static com.chuanjiabao.wisdom.bean.Constants.UPDATE_LOAD_HOME;
import static com.chuanjiabao.wisdom.bean.Constants.UPDATE_LOAD_PERSON;
import static com.chuanjiabao.wisdom.bean.Constants.URL_POST_CALL_BACK;

public class UpdateService extends Service {

    public static final String MESSAGE_ACTION = "org.feng.message_ACTION";
    public static final String HEART_BEAT_ACTION = "org.feng.heart_beat_ACTION";
    String relation = "", lucky = "";
    ReceiveBroadCast receiveBroadCast;
    List<UpdateFileTeam> listTeams = new ArrayList<>();

    private UpdateFileTeamDao teamDao = FApplication.getInstance().getDaoSession().getUpdateFileTeamDao();
    private UpdatePermissionCallBackBean.DataBean dataBean;
    private OSSClient client;
    private String currentUploadId = "";
    private String currentObjectName = "";
    private boolean hasDestory, hasStopped, hasWifiEnable;
    private Observer<String> mObserver;

    /**
     * 声明接收扫描结果的广播，
     */
    class ReceiveBroadCast extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if ("MODULE_ABOUT_RELATION".equals(action)) {
                lucky = intent.getStringExtra("module_relation");
                LogUtil.e("服务接收-->" + lucky);

                String funcation = intent.getStringExtra("module_funcation");
                if (!TextUtils.isEmpty(funcation)) {
                    if ("1".equals(funcation)) {
                        LogUtil.e("取消");

                        String uploadId = intent.getStringExtra("module_upload");
                        String objectName = intent.getStringExtra("module_object");

                        if (dataBean != null
                                && !TextUtils.isEmpty(uploadId)
                                && !TextUtils.isEmpty(objectName)
                        ) {
                            //取消分片上传
                            AbortMultipartUploadRequest abort =
                                    new AbortMultipartUploadRequest(
                                            dataBean.getBucket(),
                                            objectName,
                                            uploadId
                                    );
                            try {
                                AbortMultipartUploadResult abortResult = client.abortMultipartUpload(abort);
                                LogUtil.i("abort", abortResult.toString());
                            } catch (ClientException e) {
                                e.printStackTrace();
                            } catch (ServiceException e) {
                                e.printStackTrace();
                            }
                        } else {
                            if (!TextUtils.isEmpty(currentUploadId)) {
                                //取消分片上传
                                AbortMultipartUploadRequest abort =
                                        new AbortMultipartUploadRequest(
                                                dataBean.getBucket(),
                                                currentObjectName,
                                                currentUploadId
                                        );
                                try {
                                    AbortMultipartUploadResult abortResult = client.abortMultipartUpload(abort);
                                    LogUtil.i("abort", abortResult.toString());
                                } catch (ClientException e) {
                                    e.printStackTrace();
                                } catch (ServiceException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    } else if ("2".equals(funcation)) {
                        LogUtil.e("暂停");
                        String uploadId = intent.getStringExtra("module_upload");
                        if (TextUtils.equals(currentUploadId, uploadId)) hasStopped = true;
                    } else if ("3".equals(funcation)) {
                        LogUtil.e("继续");
                        hasStopped = false;
                    } else if ("4".equals(funcation)) {
                        LogUtil.e("退出");
                        hasDestory = true;
                    } else if ("5".equals(funcation)) {
                        LogUtil.e("开启wifi");
                        if (!TextUtils.isEmpty(currentUploadId)) hasWifiEnable = true;
                    }
                }
            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                ConnectivityManager mConnectivityManager =
                        (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();

                if (mNetworkInfo != null
                        && mNetworkInfo.isAvailable()
                ) {
                    if (TextUtils.equals("1", SpResourceUtil.getWifiStatus())) {
                        int type = mNetworkInfo.getType();
                        if (type != 1 && !TextUtils.isEmpty(currentUploadId)) hasWifiEnable = true;
                    }
                } else {
                    if (!TextUtils.isEmpty(currentUploadId)) hasWifiEnable = true;
                }
            }
        }
    }

    String fileType = "", updateType, first;

    public void setInfo(String file_cate, String home_id, String token, String relation, String filePath) {
        LogUtil.e("上传数据之file_cate-->" + file_cate);
        LogUtil.e("上传数据之home_id-->" + home_id);
        LogUtil.e("上传数据之token-->" + token);
        LogUtil.e("lucky-->" + lucky);
        if (!lucky.equals("暂无") && !TextUtils.isEmpty(lucky)) {
            relation = lucky;
        } else {
            LogUtil.e("服务接收-->" + relation);
            this.relation = relation;
        }

        if (TextUtils.isEmpty(relation)) {
            relation = "";
        }

        LogUtil.e("上传数据之relation-->" + relation);

        switch (file_cate) {
            case UPDATE_LOAD_HOME:
                updateType = "1";
                break;
            case UPDATE_LOAD_PERSON:
                updateType = "2";
                home_id = "";
                break;
            default:
        }
        if (ImageUtil.imgOrVideo(this, filePath)) {
            fileType = "1";
            first = filePath;
        } else {
            fileType = "2";
            first = filePath;
        }

        UpdateFileTeam t = new UpdateFileTeam();
        t.setFileName(filePath);
        t.setFileType(fileType);
        t.setStatus("ready");
        t.setFileCate(file_cate);
        t.setToken(token);
        t.setRelation(relation);
        t.setCurrentSize("0");  //上传百分比
        t.setDownloadSize("0"); //前一秒上传大小
        t.setAllSize(new File(filePath).length() + ""); //文件大小
        t.setHomeId(home_id);
        t.setUpdateType(updateType);
        t.setFirst(first);
        t.setSecond("0"); //已上传大小
        t.setThird("");   //分片上传的uploadId
        t.setForth("");   //分片上传的objectName
        t.setFifth("");
        listTeams = teamDao.loadAll();
        for (UpdateFileTeam team : listTeams) {
            if (team.getFileName().equals(filePath)) {
                ToastUtil.showToast("文件重复");
                return;
            }
        }
        teamDao.insert(t);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        receiveBroadCast = new ReceiveBroadCast();
        IntentFilter filter = new IntentFilter();
        filter.addAction("MODULE_ABOUT_RELATION");
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        }
        registerReceiver(receiveBroadCast, filter);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            mObserver = s -> {
                if (TextUtils.equals("disconnected", s)) {
                    if (!TextUtils.isEmpty(currentUploadId))
                        hasWifiEnable = true;
                } else {
                    if (TextUtils.equals("1", SpResourceUtil.getWifiStatus())
                            && !TextUtils.equals("wifi", s)
                    ) {
                        if (!TextUtils.isEmpty(currentUploadId)) hasWifiEnable = true;
                    }
                }
            };
            NetworkCallbackImpl.networkState.observeForever(mObserver);
        }

        new HomeUpdateThread().start();
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return bind;
    }

    public MyBinder bind = new MyBinder();

    public class MyBinder extends Binder {
        public UpdateService getService() {
            return UpdateService.this;
        }
    }

    boolean updateOver = true;

    class HomeUpdateThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (!hasDestory) {
                if (teamDao.loadAll().size() != 0 && updateOver) {
                    boolean isContinue = true;

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        if (TextUtils.equals("1", SpResourceUtil.getWifiStatus())) {
                            boolean isWifi =
                                    TextUtils.equals(
                                            "wifi",
                                            NetworkCallbackImpl.networkState.getValue()
                                    );
                            if (!isWifi) isContinue = false;
                        }
                    } else {
                        if (TextUtils.equals("1", SpResourceUtil.getWifiStatus())) {
                            boolean isWifi = ToolUtil.isWifiConnected(UpdateService.this);
                            if (!isWifi) isContinue = false;
                        }
                    }

                    if (isContinue) {
                        listTeams = teamDao.loadAll();
                        if (!listTeams.isEmpty()) {
                            UpdateFileTeam item = CollectionsKt.firstOrNull(
                                    listTeams,
                                    updateFileTeam -> !TextUtils.equals("stop", updateFileTeam.getStatus())
                            );

                            if (item != null) {
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                                    boolean isNetwork =
                                            !TextUtils.equals(
                                                    "disconnected",
                                                    NetworkCallbackImpl.networkState.getValue()
                                            );
                                    if (isNetwork) {
                                        updateOver = false;
                                        hasStopped = false;
                                        hasWifiEnable = false;
                                        getUpdatePermission(item);
                                    }
                                } else {
                                    boolean isNetwork = ToolUtil.isNetworkConnected(UpdateService.this);
                                    if (isNetwork) {
                                        updateOver = false;
                                        hasStopped = false;
                                        hasWifiEnable = false;
                                        getUpdatePermission(item);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    @Override
    public void onDestroy() {
        if (receiveBroadCast != null) {
            unregisterReceiver(receiveBroadCast);
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            if (mObserver != null) {
                NetworkCallbackImpl.networkState.removeObserver(mObserver);
            }
        }

        super.onDestroy();
    }

    public void getUpdatePermission(final UpdateFileTeam team) {
        try {
            String token = SpResourceUtil.getToken();
            Response response = OkGo.post(Constants.ULR_POST_UPDATA)
                    .connTimeOut(30000)
                    .headers("token", token)
                    .params("type", team.getUpdateType())
                    .params("id", team.getHomeId())
                    .execute();

            String s = response.body().string();
            if (!StringUtil.isFail(s)) {
                updateOver = true;
                StringUtil.showFail(UpdateService.this, s);
            } else {
                updateOver = false;
                final UpdatePermissionCallBackBean backBean = GsonUtil.GsonToBean(s, UpdatePermissionCallBackBean.class);
                dataBean = backBean.getData();
                updateMethod(team);
            }
        } catch (IOException e) {
            e.printStackTrace();
            updateOver = true;
        }
    }

    public void updateMethod(final UpdateFileTeam team) {
        OSSCredentialProvider credentialProvider = new OSSStsTokenCredentialProvider(
                dataBean.getAccessKeyId(),
                dataBean.getAccessKeySecret(),
                dataBean.getSecurityToken()) {
            @Override
            public OSSFederationToken getFederationToken() {
                return super.getFederationToken();
            }
        };
        ClientConfiguration conf = new ClientConfiguration();
        conf.setConnectionTimeout(15 * 1000);
        conf.setSocketTimeout(15 * 1000);
        conf.setMaxConcurrentRequest(5);
        conf.setMaxErrorRetry(2);
        OSSLog.enableLog();
        client = new OSSClient(
                UpdateService.this,
                "https://" + dataBean.getEndPoint(),
                credentialProvider,
                conf
        );

        //上传文件命名
        int index = team.getFileName().lastIndexOf(".");
        int random = new Random().nextInt(999) % 900 + 100;
        String name = String.valueOf(System.currentTimeMillis()) +
                random +
                SpResourceUtil.getUserId() +
                team.getFileName().substring(index);

        ListPartsResult resultBefore;
        ArrayList tagList = new ArrayList<PartETag>();

        try {
            if (TextUtils.isEmpty(team.getThird())) {
                //初始化分片上传
                InitiateMultipartUploadRequest init =
                        new InitiateMultipartUploadRequest(
                                dataBean.getBucket(),
                                dataBean.getObj() + name
                        );

                //获取分片上传的UploadId
                InitiateMultipartUploadResult initResult = client.initMultipartUpload(init);
                currentUploadId = initResult.getUploadId();
                currentObjectName = dataBean.getObj() + name;

                //保存上传Id
                team.setThird(currentUploadId);
                team.setForth(dataBean.getObj() + name);
                teamDao.update(team);
            } else {
                currentUploadId = team.getThird();
                currentObjectName = team.getForth();
            }
        } catch (ClientException e) {
            e.printStackTrace();
        } catch (ServiceException e) {
            e.printStackTrace();
        }

        if (TextUtils.isEmpty(currentUploadId)) {
            teamDao.delete(team);
            updateOver = true;
            ToastUtil.showToast("文件上传失败，请重新上传");
            return;
        }

        try {
            //列举分片
            ListPartsRequest listParts =
                    new ListPartsRequest(
                            dataBean.getBucket(),
                            team.getForth(),
                            currentUploadId
                    );

            List<PartSummary> items = new ArrayList<>();

            do {
                resultBefore = client.listParts(listParts);
                items.addAll(resultBefore.getParts());
                if (resultBefore.isTruncated()) {
                    int partNumber = resultBefore.getNextPartNumberMarker();
                    listParts.setPartNumberMarker(partNumber);
                }
            } while (resultBefore.isTruncated());

            for (PartSummary item : items) {
                tagList.add(new PartETag(item.getPartNumber(), item.getETag()));
            }

            //确保最后一个分片完整
            if (!tagList.isEmpty()) {
                int size = tagList.size();
                tagList.remove(size - 1);
            }
        } catch (ClientException e) {
            e.printStackTrace();
        } catch (ServiceException e) {
            e.printStackTrace();
        }

        int partCount = 500 * 1024;
        long fileTotal = Long.parseLong(team.getAllSize());

        int parts = (int) Math.ceil(fileTotal * 1.0 / partCount);
        int lastPart = (int) (fileTotal - ((parts - 1) * partCount));

        try {
            for (int i = 1; i <= parts; i++) {
                if (tagList.size() < i) {
                    byte[] data = new byte[i == parts ? lastPart : partCount];
                    RandomAccessFile raf = new RandomAccessFile(team.getFileName(), "r");
                    long skip = (i - 1) * partCount;
                    raf.seek(skip);
                    raf.readFully(data, 0, i == parts ? lastPart : partCount);

                    UploadPartRequest uploadPart = new UploadPartRequest();
                    uploadPart.setBucketName(dataBean.getBucket());
                    uploadPart.setObjectKey(team.getForth());
                    uploadPart.setUploadId(currentUploadId);
                    uploadPart.setPartNumber(i);
                    uploadPart.setPartContent(data);
                    UploadPartResult result = client.uploadPart(uploadPart);

                    tagList.add(new PartETag(i, result.getETag()));
                    long currentSize = i == parts ? fileTotal : (i * partCount);
                    int pressent = (int) ((float) currentSize / fileTotal * 100);
                    team.setCurrentSize(pressent + "");
                    team.setSecond(currentSize + "");
                    team.setStatus("start");
                }

                if (hasStopped) {
                    team.setStatus("stop");
                    teamDao.update(team);
                    currentUploadId = "";
                    updateOver = true;
                    return;
                }

                if (hasWifiEnable) {
                    currentUploadId = "";
                    updateOver = true;
                    return;
                }

                if (hasDestory) {
                    currentUploadId = "";
                    return;
                }
            }

            //完成分片上传
            CompleteMultipartUploadRequest complete =
                    new CompleteMultipartUploadRequest(
                            dataBean.getBucket(),
                            team.getForth(),
                            currentUploadId,
                            tagList);

            complete.setCallbackParam(new HashMap<String, String>() {
                {
                    put("callbackUrl", URL_POST_CALL_BACK);
                    put("callbackBody", "bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}" +
                            "&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}" +
                            "&imageInfo.format=${imageInfo.format}&token=${x:token}&home_id=${x:home_id}" +
                            "&file_cate=${x:file_cate}&relation=${x:relation}&creatTime=${x:creatTime}");
                }
            });

            long time = new File(team.getFileName()).lastModified();
            try {
                ExifInterface exifInterface = new ExifInterface(team.getFileName());
                String dateTime = exifInterface.getAttribute(ExifInterface.TAG_DATETIME);
                if (dateTime != null) {
                    long exifTime = TimeHelper.getInstance().stringToLong("yyyy:MM:dd HH:mm:ss", dateTime);
                    if (exifTime > -1) time = exifTime;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            long finalTime = time;

            complete.setCallbackVars(new HashMap<String, String>() {
                {
                    put("x:token", SpResourceUtil.getToken());
                    put("x:home_id", team.getHomeId());     //家ID
                    put("x:file_cate", team.getFileCate()); // home代表家 person代表个人私密
                    put("x:relation", team.getRelation());  //关系数据，用英文,分割，仅在家类型下有效
                    put("x:creatTime", finalTime + "");     //时间戳
                }
            });

            CompleteMultipartUploadResult completeResult = client.completeMultipartUpload(complete);
            LogUtil.i("complete", completeResult.getServerCallbackReturnBody());

            currentUploadId = "";
            teamDao.delete(team);
            updateOver = true;
        } catch (IOException e) {
            e.printStackTrace();

            currentUploadId = "";
            updateOver = true;
        } catch (ClientException e) {
            e.printStackTrace();

            currentUploadId = "";
            updateOver = true;
        } catch (ServiceException e) {
            LogUtil.e("ErrorCode", e.getErrorCode());
            LogUtil.e("RequestId", e.getRequestId());
            LogUtil.e("HostId", e.getHostId());
            LogUtil.e("RawMessage", e.getRawMessage());
            LogUtil.e("status", e.getStatusCode() + "");

            currentUploadId = "";
            teamDao.delete(team);
            updateOver = true;
        }
    }

}
